#include "../../../Include/Core/File/WizFile.hpp"

namespace Wiz
{
    namespace File
    {
        ::Wiz::Bool::Type Exist(::Wiz::String::In InStr)
        {
            ::Wiz::File::Ptr TempPtr = ::fopen(InStr.GetCStr(), "r");
            if (::Wiz::NotValidPtr(TempPtr))
            {
                return ::Wiz::Bool::False;
            }

            ::Wiz::File::Close(TempPtr);
            return ::Wiz::Bool::True;
        }

        ::Wiz::Bool::Type CreateEmptyFile(::Wiz::String::In InStr)
        {
            ::Wiz::File::Ptr TempPtr = ::fopen(InStr.GetCStr(), "a");
            if (::Wiz::NotValidPtr(TempPtr))
            {
                return ::Wiz::Bool::False;
            }

            ::Wiz::File::Close(TempPtr);
            return ::Wiz::Bool::True;
        }

        ::Wiz::Bool::Type ReadFileToBuffer(::Wiz::ByteBuffer::Out OutBuff, ::Wiz::String::In InStr)
        {
            ::Wiz::File::Ptr TempPtr = ::Wiz::File::Open(InStr.GetCStr(), ::Wiz::File::OpenOptions::eOpenRead);
            if (::Wiz::NotValidPtr(TempPtr))
            {
                return ::Wiz::Bool::False;
            }

            ::Wiz::File::MoveToEnd(TempPtr);
            OutBuff.Resize(::Wiz::File::CurrentPosition(TempPtr));

            ::Wiz::File::MoveToBegin(TempPtr);
            ::Wiz::File::Read(TempPtr, OutBuff.GetPtr(), OutBuff.GetElementCount());

            ::Wiz::File::Close(TempPtr);
            return ::Wiz::Bool::True;
        }

        ::Wiz::Bool::Type WriteBufferToFile(::Wiz::ByteBuffer::In InBuffer, ::Wiz::String::In InStr)
        {
            ::Wiz::File::Ptr TempPtr = ::Wiz::File::Open(InStr.GetCStr(), ::Wiz::File::OpenOptions::eOpenWrite);
            if (::Wiz::NotValidPtr(TempPtr))
            {
                return ::Wiz::Bool::False;
            }

            ::Wiz::File::Write(TempPtr, InBuffer.GetPtr(), InBuffer.GetElementCount());
            ::Wiz::File::Close(TempPtr);
            return ::Wiz::Bool::True;
        }

        namespace LargeFileTask
        {
            ::Wiz::Bool::Type Initialize(::Wiz::File::LargeFileTask::Out OutTask, ::Wiz::String::In InFileName)
            {
                ::Wiz::File::Ptr TempPtr = ::Wiz::File::Open(InFileName, ::Wiz::File::OpenOptions::eOpenRead | ::Wiz::File::OpenOptions::eOpenWrite);
                if (::Wiz::NotValidPtr(TempPtr))
                {
                    return ::Wiz::Bool::False;
                }

                ::Wiz::File::MoveToEnd(TempPtr);
                OutTask.m_TotalLength = ::Wiz::File::CurrentPosition(TempPtr);
                OutTask.m_CurrentPosition = 0;

                if (::Wiz::IsValidPtr(OutTask.m_StreamHandler))
                {
                    ::Wiz::File::Close(OutTask.m_StreamHandler);
                }
                OutTask.m_StreamHandler = TempPtr;
                return ::Wiz::Bool::True;
            }

            ::Wiz::Bool::Type Read(::Wiz::File::LargeFileTask::InOut OutTask)
            {
                if (::Wiz::NotValidPtr(OutTask.m_StreamHandler))
                {
                    return ::Wiz::Bool::False;
                }

                OutTask.m_CurrentPosition += OutTask.m_Availability;

                ::Wiz::File::MoveTo(OutTask.m_StreamHandler, OutTask.m_CurrentPosition);
                ::Wiz::Int64::Type Availability =
                    ::Wiz::Min2(OutTask.m_TotalLength - OutTask.m_CurrentPosition, OutTask.m_MaxSize);
                OutTask.m_Availability =
                    ::Wiz::File::Read( OutTask.m_StreamHandler, OutTask.GetPtr(), Availability);

                return OutTask.m_Availability ==  Availability;
            }

            ::Wiz::Bool::Type Write(::Wiz::File::LargeFileTask::InOut OutTask)
            {
                if (::Wiz::NotValidPtr(OutTask.m_StreamHandler))
                {
                    return ::Wiz::Bool::False;
                }

                ::Wiz::File::MoveTo(OutTask.m_StreamHandler, OutTask.m_CurrentPosition);

                ::Wiz::Int64::Type Availability =
                    ::Wiz::Min2(OutTask.m_Availability, OutTask.m_MaxSize);

                ::Wiz::File::Write(OutTask.m_StreamHandler, OutTask.GetPtr() + OutTask.m_CurrentPosition, Availability);

                return ::Wiz::Bool::True;
            }
        } /// end of namespace LargeFileTask
    } /// end of namespace File
} /// end of namespace Wiz
